package com.enjoy.anno;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.annotation.Method;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.registry.Registry;
import com.alibaba.dubbo.registry.RegistryFactory;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.service.GenericService;
import com.enjoy.inJvm.StudentService;
import com.xiangxue.jack.async.AsyncService;
import com.xiangxue.jack.callback.CallbackListener;
import com.xiangxue.jack.callback.CallbackService;
import com.xiangxue.jack.group.Group;
import com.xiangxue.jack.mock.MockService;
import com.xiangxue.jack.service.UserService;
import com.xiangxue.jack.validation.ValidationParamter;
import com.xiangxue.jack.validation.ValidationService;
import com.xiangxue.jack.version.VersionService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * dubbo 消费者测试类
 *
 * @Author Ellison Pei
 * @Date 2021/7/14 09:20
 **/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AnnoBean.class)
public class AnnoTests {
    // 要使用`Dubbo`的注解
    // check 启动前检查服务是否存在，为true时，检查没有会报错；为false不检查
    // retries 重试次数 默认是 2、

    @Reference(check = false, retries = 3, cluster = "failover", loadbalance = "random")
    UserService userService;

    /**
     * 指定想要调用的实现类
     */
    @Reference(check = false, group = "groupImpl1")
    Group group1;
    /**
     * 合并两个实现类的结果，源码中没有合并String类型的实现逻辑，我们需要自己写String类型的合并逻辑
     */
    @Reference(check = false, group = "*", parameters = {"merger", "true"})
    Group group;

    /**
     * 指定版本发布实现类，发布部分实例，实现灰度发布
     */
    @Reference(check = false, version = "1.0.1")
    VersionService versionService;

    /**
     * validation校验在dubbo中的使用
     */
    @Reference(check = false, validation = "true")
    ValidationService validationService;

    @Reference(check = false, interfaceClass = GenericService.class)
    GenericService genericService;

    @Reference(check = false, timeout = 1000000000, methods = {@Method(name = "asynctoDo", async = true), @Method(name = "doTwo", async = true), @Method(name = "doOne", async = true)})
    AsyncService asyncService;

    //本工程有这个实现了该接口的实例，可以直接反射调用
    @Reference(check = false, injvm = true)
    StudentService studentService;

    @Reference(check = false)
    CallbackService callbackService;

    // 本地存根
//    @Reference(check = false, stub = "cn.enjoy.stub.LocalStubProxy")
//    StubService stubService;

    //这两种方式会走rpc远程调用  fail -- 会走远程服务
//  @Reference(check = false,mock = "true")
//  @Reference(check = false, mock = "cn.enjoy.mock.LocalMockService")

    //不走服务直接降级  force -- 是不会走远程服务的，强制降级..这种方式是用dubbo-admin去配置它，服务治理的方式
    @Reference(check = false, mock = "force:return jack")
    MockService mockService;


    /**
     * 野路子
     * 设置属性值
     */
    @Test
    public void test1() {
        //  RpcContext rpcContext = RpcContext.getContext();
        //  rpcContext.setAttachment("retries", "5");
        System.out.println(userService.queryUser("44444"));
    }

    @Test
    public void testAnno() {
        System.out.println(userService.queryUser("22"));
        System.err.println(userService.queryUser("阿斯顿发送到发送到"));
    }

    /**
     * 以API的形式去消费
     * 此种方式 和 注解 AnnoBean.class中 @PropertySource("dubbo.properties") 二选一
     */
    @Test
    public void api() {
//        运行时，把 AnnoBean.class中 @PropertySource("dubbo.properties") 注释掉
//        ApplicationConfig applicationConfig = new ApplicationConfig();
//        applicationConfig.setName("dubbo_consumer");
//
//        RegistryConfig registryConfig = new RegistryConfig();
//        registryConfig.setAddress("zookeeper://119.3.228.104:2181");
//
//        ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<UserService>();
//        referenceConfig.setApplication(applicationConfig);
//        referenceConfig.setRegistry(registryConfig);
//        referenceConfig.setInterface(UserService.class);
//        UserService userService = referenceConfig.get();
//        System.out.println(userService.queryUser("000"));

    }

    @Test
    public void group() {
        System.err.println(group.doSomething("er"));
    }

    @Test
    public void versionTest() {
        System.err.println(versionService.version("444444"));
    }

    @Test
    public void validation() {
        ValidationParamter paramter = new ValidationParamter();
        paramter.setName("Jack");
        paramter.setAge(98);
        paramter.setLoginDate(new Date(System.currentTimeMillis() - 10000000));
        paramter.setExpiryDate(new Date(System.currentTimeMillis() + 10000000));
        validationService.save(paramter);
    }

    /**
     * 只能用于测试
     */
    @Test
    public void usegeneric() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo_consumer");

        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://119.3.228.104:2181");

        ReferenceConfig<GenericService> referenceConfig = new ReferenceConfig<>();
        referenceConfig.setApplication(applicationConfig);
        referenceConfig.setInterface("com.xiangxue.jack.service.UserService");
        //这个是使用泛化调用
        referenceConfig.setGeneric(true);
        GenericService genericService = referenceConfig.get();

        Object result = genericService.$invoke("queryUser", new String[]{"java.lang.String"}, new Object[]{"Jack"});
        System.out.println(result);
    }

    @Test
    public void implgeneric() {
        Object eat = genericService.$invoke("eat", new String[]{"java.lang.String"}, new Object[]{"jakc"});
        System.out.println(eat);
    }

    @Test
    public void async() throws ExecutionException, InterruptedException {
        String aa = asyncService.asynctoDo("aa");
        System.out.println("main====" + aa);
        //这里是主线程阻塞等待返回结果
        Object o = RpcContext.getContext().getFuture().get();
        System.out.println(o);
    }

    /**
     * 这么用生产者会报错
     * Serialized class java.util.concurrent.CompletableFuture must implement java.io.Serializable
     */
    @Test
    public void asyncCompletableFuture() {
        CompletableFuture<String> doOne = asyncService.doOne("doOne");
        String doTwo = asyncService.doTwo("doTwo");
        doOne.whenComplete((result, throwable) -> {
            if (throwable != null) {
                throwable.printStackTrace();
            } else {
                System.out.println("异步调用提供者的doOne的返回值" + result);
            }
        });
        System.out.println("调用doTwo的返回值：" + doTwo);
    }

    @Test
    public void inJvm() throws InterruptedException {
        System.out.println(studentService.find("xx"));
        Thread.currentThread().join();
    }

    @Test
    public void paramCallback() {
        callbackService.addListener("jack", new CallbackListener() {
            //这个方法就会被服务端回调
            @Override
            public void changed(String s) {
                System.out.println("========修改订单表状态=========，由未支付变成支付==" + s);
            }
        });
    }


//    @Test
//    public void stub() {
//        System.out.println(stubService.stub("jack"));
//    }

    @Test
    public void mock() {
        System.out.println(mockService.mock("jack"));
    }

    /**
     * 以 API 的形式去修改 override
     */
    @Test
    public void override() {
        RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
        Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://119.3.228.104:2181"));
        //    override:// 目的是为了在运行时区覆盖属性的，比如timeout
        registry.register(URL.valueOf("override://0.0.0.0/com.xiangxue.jack.service.UserService?category=configurators&dynamic=false&application=dubbo_consumer&timeout=9000"));
    }


}
